using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using NUnit.Framework.Extensions;
namespace lang_benchmarks
{
    public interface ISumator<T>
    {
        T Add(T a, T b);
    }

    public abstract class Sumator<T>
    {
        public abstract T Add(T a, T b);
    }

    public class ASumatorInt : Sumator<int>
    {
        public override int Add(int a, int b)
        {
            return a + b;
        }
    }

    public class SumatorInt : ISumator<int>
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
    }
    public class NativeSumatorInt
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
    }
    delegate T Sum<T>(T a, T b);

    [TestFixture]
    public class SumTests
    {
        double DoTestI(int n)
        {
            Timer T = new Timer();
            ISumator<int> S = new SumatorInt();
            T.Start();
            for (int i = 0; i < n; i = S.Add(i, 1)) ;
            T.Stop();
            return T.Duration;
        }
        double DoTestN(int n)
        {
            Timer T = new Timer();
            NativeSumatorInt N = new NativeSumatorInt();
            T.Start();
            for (int i = 0; i < n; i = N.Add(i, 1)) ;
            T.Stop();
            return T.Duration;
        }

        double DoTestA(int n)
        {
            Timer T = new Timer();
            Sumator<int> N = new ASumatorInt();
            T.Start();
            for (int i = 0; i < n; i = N.Add(i, 1)) ;
            T.Stop();
            return T.Duration;
        }

        int add(int a, int b)
        {
            return a + b;
        }

        double DoTestGen<TT>(int n) where TT : ISumator<int>,new()
        {
            Timer Ti = new Timer();
            TT Gen = new TT();
            Ti.Start();
            for (int i = 0; i < n; i = Gen.Add(i, 1)) ;
            Ti.Stop();
            return Ti.Duration;
        }

        double DoTestD(int n)
        {
            Timer T = new Timer();
            Sum<int> S = add; 
            T.Start();
            for (int i = 0; i < n; i =S(i, 1)) ;
            T.Stop();
            return T.Duration;
        }

        [Test]
        public void SumTest()
        {
            Console.WriteLine("Interface , nonInterface, abstract, delegate , generic");
            for (int j = 0; j < 10; j++)
            {

                int n = 100000;
                double t1 = 0, t2 = 0 ,t3 = 0 , t4 =0, t5 = 0 ;
                for (int i = 0; i < 100; i++)
                {
                    t1 += DoTestI(n);
                    t2 += DoTestN(n);
                    t3 += DoTestA(n);
                    t4 += DoTestD(n);
                    t5 += DoTestGen<SumatorInt>(n);
                }
                Console.WriteLine(t1.ToString("F6") + "  " + t2.ToString("F6") + "  " + t3.ToString("F6") + "  " + t4.ToString("F6") + "  " + t5.ToString("F6"));
            }
        }
    }
}
